package com.wrbug.mmkw.compile.generator

import com.squareup.javapoet.*
import com.youzan.router.compile.generator.Generator
import javax.annotation.processing.Filer
import javax.lang.model.element.Modifier

/**
 *   FinderGenerator.kt
 *   author: wrbug
 *   date: 2019-09-24 20:30
 *
 */
class FinderGenerator(private val mFiler: Filer, private val list: ArrayList<ClassName>) : Generator {
    companion object {
        val FINDER_CLASS = ClassName.get("com.wrbug.mmkw.runtime", "MMKWFinder")
        const val GET_METHOD = "get"
        const val CACHE_FIELD = "CACHE"
        const val CLAZZ_NAME = "clazz"
    }

    override fun generate() {
        try {
            val javaFile =
                JavaFile.builder(FINDER_CLASS.packageName(), buildTypeSpec())
                    .build()
            javaFile.writeTo(mFiler)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }


    private fun buildTypeSpec() =
        TypeSpec.classBuilder(FINDER_CLASS)
            .addField(
                FieldSpec.builder(
                    ParameterizedTypeName.get(Map::class.java, Class::class.java, Any::class.java),
                    CACHE_FIELD,
                    Modifier.PRIVATE,
                    Modifier.STATIC,
                    Modifier.FINAL
                )
                    .initializer("new \$T()", HashMap::class.java).build()
            )
            .addMethod(buildGetMethod()).build()

    private fun buildGetMethod(): MethodSpec? {
        val builder = MethodSpec.methodBuilder(GET_METHOD).addModifiers(Modifier.PUBLIC, Modifier.STATIC)
            .addParameter(Class::class.java, CLAZZ_NAME, Modifier.FINAL)
            .returns(Any::class.java)
        builder.beginControlFlow("if(\$L.containsKey(\$L))", CACHE_FIELD, CLAZZ_NAME)
            .addStatement("return \$L.get(\$L)", CACHE_FIELD, CLAZZ_NAME)
            .endControlFlow()
        builder.addStatement("Object obj=null")
        list.forEach {
            builder.beginControlFlow("if (\$L==\$T.class)", CLAZZ_NAME, it)
                .addStatement("obj=\$L.\$LImpl.getInstance()", it.packageName(), it.simpleName())
                .addStatement("\$L.put(\$L,\$L)", CACHE_FIELD, CLAZZ_NAME, "obj")
                .addStatement("return obj")
                .endControlFlow()
        }
        builder.addStatement("return obj")
        return builder.build()
    }


}